<?php
// +-------------------------------------------------------------------------------
// | DingZone [ A Rapid Development Framework For Dingtalk ]
// +-------------------------------------------------------------------------------
// | BeanController.php v1.0
// |
// | Copyright (c) 2014-2018 http://www.heimalanshi.com All rights reserved.
// | Author : Jie
// | Date : 2018-10-11
// +-------------------------------------------------------------------------------


namespace app\core\common\bean;


use app\core\model\CacheKey;
use app\extend\db\TableInfoHelper;
use think\Config;
use think\Db;
use think\db\Expression;

trait BeanController {

    protected function _getDbConfig() {
        return [];
    }

    /**
     * 获取某张表的查询对象
     *
     * @param bool $name
     * @return \think\db\Query
     * @throws \think\Exception
     */
    protected function _q($name = false) {
        if (!isset($name) || !$name) {
            $name = $this->_getTableName();
        }
        $dbConfig = array_merge(Config::get("database"), $this->_getDbConfig());
        return Db::connect($dbConfig)->name($name);
    }

    /**
     * 获取字段的不重复值列表
     *
     * @param $field
     * @param int $limit
     * @param int $expire
     * @return array|mixed
     * @throws \think\Exception
     */
    protected function _distinct($field, $limit = 100, $expire = 3600) {
        $cacheKey = CacheKey::module()->type($this->_getBeanName() . "_distinct_value")->tags([
            'eid' => $this->eid,
            'limit' => $limit,
            'field' => $field
        ]);
        if ($expire) {
            $values = $cacheKey->getValue();
            if (!empty($values)) {
                return $values;
            }
        }
        $conditions = [];
        if ($this->_enableEid()) {
            $conditions['enterprise_id'] = $this->eid;
        }
        if ($this->_isSoftDelete()) {
            $conditions['is_deleted'] = 0;
        }
        $values = $this->_q()->where($conditions)->distinct(true)->limit($limit)->column($field);
        if ($expire) {
            $cacheKey->setValue($values, $expire);
        }
        return $values;
    }

    /**
     * 清除字段不重复缓存
     *
     * @throws \think\Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     * @throws \think\exception\PDOException
     */
    protected function _clearDistinctCache() {
        CacheKey::remove($this->_getBeanName() . "_distinct_value");
    }

    /**
     * 获取bean名称
     *
     * @return string
     */
    protected abstract function _getBeanName();

    /**
     * bean标题
     *
     * @return string
     */
    protected function _getBeanTitle() {
        return $this->_getBeanName();
    }

    /**
     * 数据表名称
     *
     * @return string
     */
    protected function _getTableName() {
        return $this->_getBeanName();
    }

    /**
     * 获取页面标题
     *
     * @param $action
     * @return string
     */
    protected function _getPageTitle($action) {
        $beanTitle = $this->_getBeanTitle();
        switch ($action) {
            case 'all':
            case 'mobile':
                return $beanTitle . lang("LIST");
            case 'add':
                return lang("ADD") . $beanTitle;
            case 'edit':
                return lang("EDIT") . $beanTitle;
            case 'del':
                return lang("DEL") . $beanTitle;
        }
        return "";
    }

    /**
     * 获取bean字段配置
     *
     * @return array
     * @throws \think\Exception
     * @throws \think\exception\PDOException
     */
    protected function _getBeanFieldsConfig() {
        return $this->_getDefaultBeanFieldsConfig();
    }

    /**
     * 获取默认的bean字段配置
     *
     * @return array
     * @throws \think\Exception
     * @throws \think\exception\PDOException
     */
    protected function _getDefaultBeanFieldsConfig() {
        //获取物理表的字段信息
        $tableName = $this->_getTableName();
        $tableColumnInfos = TableInfoHelper::getColumns($tableName, $this->_getDbConfig());

        //获取页面的隐藏字段配置
        if (method_exists($this, "_getEnterpriseConfig")) {
            $colsShowConfig = $this->_getEnterpriseConfig(
                $this->request->module() . "/" . $this->request->controller() . "/" . $this->request->action() .
                "/*/BEAN_COLS_SHOW_CONFIG", "");
            $colsShowConfig = empty($colsShowConfig) ? [] : json_decode($colsShowConfig, true);
        } else {
            $colsShowConfig = [];
        }

        $idx = 0;
        $fieldsConfig = [];
        foreach ($tableColumnInfos as $tableColumnInfo) {
            $field = strtolower($tableColumnInfo['Field']);
            $type = $tableColumnInfo['Type'];
            $comment = $tableColumnInfo['Comment'];

            //标题默认是列的注释，如果没设置注释，默认为列名
            $langCode = "BEAN_TITLE_" . strtoupper($field);
            $title = lang($langCode);
            if (empty($title) || $title == $langCode) {
                $title = $comment ? $comment : $field;
            }

            $fieldConfig = [
                BFC::TITLE => $title
            ];

            //排序
            if (TableInfoHelper::isColumnTypeNumeric($type)) {
                //如果列是数字类型，默认支持排序
                $fieldConfig[BFC::SORT] = true;
            }

            //列是否隐藏
            $show = fetch($colsShowConfig, $field, null);

            //处理规则约定的列
            switch ($field) {
                case "id":
                    //列名为id，则为主键
                    $fieldConfig[BFC::KEY] = true;
                    if ($show === null) {
                        $show = false;
                    }
                    break;
                case "gmt_created":
                case "gmt_modified":
                    //gmt_created、gmt_modified为时间戳类型
                    $fieldConfig[BFC::TYPE] = BFC::TYPE_TIMESTAMP;
                    if ($show === null) {
                        $show = false;
                    }
                    break;
                case "enterprise_id":
                case "is_deleted":
                    //企业ID、软删除标记默认隐藏
                    $fieldConfig[BFC::IGNORE] = true;
                    break;
            }
            if ($show === null) {
                $show = true;
            }
            if ($show == false || strtolower(strval($show)) == 'false') {
                $fieldConfig[BFC::HIDE] = true;
            } else {
                $fieldConfig[BFC::HIDE] = false;
            }

            //列的显示顺序，越小越显示在前面
            $fieldConfig[BFC::COL_INDEX] = $idx;
            $idx++;

            $fieldsConfig[$field] = $fieldConfig;
        }

        return $fieldsConfig;
    }

    /**
     * 获取默认的排序规则
     *
     * @return array
     */
    protected function _getDefaultOrder() {
        return [
            'id' => 'desc'
        ];
    }

    /**
     * 获取每行的按钮配置
     *
     * @return array
     * 'add' => [
     *      'title' => '按钮名称',
     *      'class' => '',  //按钮附加样式类名称
     *      'action' => '' //按钮对应的操作
     * ]
     */
    protected function _getRowBtns() {
        return [];
    }

    /**
     * 获取全局的按钮配置
     *
     * @return array
     */
    protected function _getGlobalBtns() {
        return [];
    }

    /**
     * 默认都有的全局按钮配置
     *
     * @return array
     */
    protected function _getDefaultGlobalBtns() {
        return [
            "refresh" => [
                BFC::TITLE => lang("REFRESH"),
                BFC::ICON => "refresh",
                BFC::POSITION => BFC::POSITION_TABLE
            ]
        ];
    }

    /**
     * 获取行高(PC) 单位px
     *
     * @return int
     */
    protected function _getRowHeight() {
        return 28;
    }

    /**
     * 获取行高(Mobile) 单位em
     *
     * @return int
     */
    protected function _getMobileRowHeight() {
        return 3;
    }

    /**
     * 获取major行高(Mobile) 单位em
     *
     * @return int
     */
    protected function _getMobileMajorRowHeight() {
        return 2;
    }

    /**
     * 是否开启行checkbox
     *
     * @return bool
     */
    protected function _enableRowCheckbox() {
        return false;
    }

    /**
     * 是否开启行radio
     *
     * @return bool
     */
    protected function _enableRowRadio() {
        return false;
    }

    /**
     * 是否开启行序号
     *
     * @return bool
     */
    protected function _enableRowNumbers() {
        return false;
    }

    /**
     * 是否开启合计
     *
     * @return bool
     */
    protected function _enableTotalRow() {
        return false;
    }

    /**
     * 表格列最小宽度
     *
     * @return boolean
     */
    protected function _getCellMinWidth() {
        return false;
    }

    /**
     * 获取分页配置
     *
     * @return array
     */
    protected function _getPageConfig() {
        return [
            'limits' => [20, 50, 100, 200, 500],//可选的分页大小
            'groups' => 5 //连续出现的页码个数
        ];
    }

    /**
     * 默认分页大小
     *
     * @return int
     */
    protected function _getDefaultPageSize() {
        return 20;
    }

    /**
     * 设置表格默认高度
     *
     * @return string
     */
    protected function _getTableHeight() {
        return 'auto';//支持格式：（1）数字（像素数）、（2）full-数字，表示浏览器高度减去指定像素值（3）auto，表示高度随数据列表而适应
    }

    /**
     * 是否自动添加eid参数
     *
     * @return bool
     */
    protected function _enableEid() {
        return true;
    }

    /**
     * 是否为软删除
     */
    protected function _isSoftDelete() {
        return true;
    }

    /**
     * 表中是否存在gmt_created字段
     *
     * @return bool
     */
    protected function _gmtCreated() {
        return true;
    }

    /**
     * 表中是否存在gmt_modified字段
     *
     * @return bool
     */
    protected function _gmtModified() {
        return true;
    }

    /**
     * 获取参数占位符
     *
     * @param $paramName
     * @return string
     */
    public static function getParamPlaceholder($paramName) {
        return "###__" . $paramName . "__###";
    }

    /**
     * 列表页
     *
     * @return \think\response\View
     * @throws \think\Exception
     * @throws \think\exception\PDOException
     */
    public function all() {
        $fieldsConfig = $this->_getBeanFieldsConfig();

        // 排序参数
        $orderParam = input("param.___order");
        list($order, $orderItems) = $this->_parseOrder($orderParam);

        // 分页参数
        $page = intval(input("param.___currPage", 1));
        $limit = intval(input("param.___pageSize", $this->_getDefaultPageSize()));

        // 列最小宽度
        $cellMinWidth = $this->_getCellMinWidth();
        if ($cellMinWidth) {
            foreach ($fieldsConfig as &$fieldConfig) {
                if (!isset($fieldConfig[BFC::MIN_WIDTH])) {
                    $fieldConfig[BFC::MIN_WIDTH] = $cellMinWidth;
                }
            }
        }

        // 表格配置
        $config = [];
        $config['rowCheckbox'] = $this->_enableRowCheckbox();
        $config['rowRadio'] = $this->_enableRowRadio();
        $config['rowNumbers'] = $this->_enableRowNumbers();
        $config['page'] = $this->_getPageConfig();
        $config['page']['limit'] = $limit;
        $config['page']['curr'] = $page;
        $config['order'] = $orderItems;
        $config['fieldsConfig'] = $this->_sortFieldsConfigByIndex($fieldsConfig);
        $config['rowBtns'] = $this->_getAuthorizedBtns($this->_getRowBtns());
        $config['globalBtns'] = $this->_getAuthorizedBtns(
            array_merge($this->_getGlobalBtns(), $this->_getDefaultGlobalBtns())
        );
        $config['rowHeight'] = $this->_getRowHeight();
        $config['height'] = $this->_getTableHeight();
        $config['totalRow'] = $this->_enableTotalRow();
        $config['globalTotalRow'] = $this->_getGlobalTotalRowConfig();

        $this->assign("__table_config", $config);
        $this->assign("pageTitle", $this->_getPageTitle($this->request->action()));

        if ($this->view->engine->exists("")) {
            return view();
        } else {
            $viewPath = realpath(ROOT_PATH . "application/core/view/common/pc/bean/all.html");
            return view($viewPath);
        }
    }

    /**
     * 数据选取列表
     *
     * @return \think\response\View
     * @throws \think\Exception
     * @throws \think\exception\PDOException
     */
    public function picker() {
        $fieldsConfig = $this->_getBeanFieldsConfig();

        // 排序参数
        $orderParam = input("param.___order");
        list($order, $orderItems) = $this->_parseOrder($orderParam);

        // 分页参数
        $page = intval(input("param.___currPage", 1));
        $limit = intval(input("param.___pageSize", $this->_getDefaultPageSize()));

        // 列最小宽度
        $cellMinWidth = $this->_getCellMinWidth();
        if ($cellMinWidth) {
            foreach ($fieldsConfig as &$fieldConfig) {
                if (!isset($fieldConfig[BFC::MIN_WIDTH])) {
                    $fieldConfig[BFC::MIN_WIDTH] = $cellMinWidth;
                }
            }
        }

        //是否多选
        $multi = input("param.___multi");

        // 表格配置
        $config = [];
        $config['rowCheckbox'] = $multi ? true : false;
        $config['rowRadio'] = $multi ? false : true;
        $config['page'] = $this->_getPageConfig();
        $config['page']['limit'] = $limit;
        $config['page']['curr'] = $page;
        $config['order'] = $orderItems;
        $config['fieldsConfig'] = $this->_sortFieldsConfigByIndex($fieldsConfig);
        $config['rowBtns'] = [];
        $config['globalBtns'] = [];
        $config['rowHeight'] = $this->_getRowHeight();
        $config['height'] = $this->_getTableHeight();
        $config['totalRow'] = $this->_enableTotalRow();

        $this->assign("__table_config", $config);
        $this->assign("__pickerId", input("param.__pickerId"));
        $this->assign("pageTitle", $this->_getPageTitle($this->request->action()));

        if ($this->view->engine->exists("")) {
            return view();
        } else {
            $viewPath = realpath(ROOT_PATH . "application/core/view/common/pc/bean/picker.html");
            return view($viewPath);
        }
    }


    /**
     * 手机列表页
     *
     * @return \think\response\View
     * @throws \think\Exception
     * @throws \think\exception\PDOException
     */
    public function mobile() {
        $fieldsConfig = $this->_getBeanFieldsConfig();

        // 分页参数
        $page = intval(input("param.___currPage", 1));
        $limit = intval(input("param.___pageSize", $this->_getDefaultPageSize()));

        // 表格配置
        $config = [];
        $config['page'] = [];
        $config['page']['limit'] = $limit;
        $config['page']['curr'] = $page;
        $config['fieldsConfig'] = $this->_sortFieldsConfigByIndex($fieldsConfig);
        $config['rowHeight'] = $this->_getMobileRowHeight();
        $config['majorRowHeight'] = $this->_getMobileMajorRowHeight();

        $this->assign("__table_config", $config);
        $this->assign("pageTitle", $this->_getPageTitle($this->request->action()));

        if ($this->view->engine->exists("")) {
            return view();
        } else {
            $viewPath = realpath(ROOT_PATH . "application/core/view/common/mobile/bean/all.html");
            return view($viewPath);
        }
    }

    /**
     * 数据查询
     *
     * @return \think\response\Json
     * @throws \think\Exception
     * @throws \think\exception\PDOException
     */
    public function data() {
        $query = $this->_q();
        $fieldsConfig = $this->_getBeanFieldsConfig();
        $fields = $this->_getSelectFields($fieldsConfig);
        $query->field(join(",", $fields));

        // 查询条件
        $conditions = $this->_getQueryConditions($fieldsConfig);
        $query = $this->_setQueryConditions($conditions, $query);

        // 排序参数
        $orderParam = input("param.___order");
        list($order, $orderItems) = $this->_parseOrder($orderParam);
        $query->order($order);

        // 分页参数
        $page = intval(input("param.___currPage", 1));
        $limit = intval(input("param.___pageSize", $this->_getDefaultPageSize()));
        $query->page($page, $limit);

        // 查询数据
        $rows = $query->select();

        // 数据总数
        $query = $this->_q();
        $query = $this->_setQueryConditions($conditions, $query);
        $total = $query->count();

        $result = [
            'code' => 0,
            'count' => $total,
            'page' => $page,
            'limit' => $limit,
            'data' => $rows,
            'msg' => '',
            'success' => true
        ];

        $result = $this->_resultPreProcess($result);

        return json($result);
    }

    /**
     * 全局汇总数据
     *
     * @throws \think\Exception
     * @throws \think\exception\PDOException
     */
    public function globalTotalRowData() {
        $query = $this->_q();
        $fieldsConfig = $this->_getBeanFieldsConfig();
        $globalTotalRowConfig = $this->_getGlobalTotalRowConfig();

        $globalTotalRowResult = [];
        if (!empty($globalTotalRowConfig)) {
            // 查询条件
            $conditions = $this->_getQueryConditions($fieldsConfig);
            $query = $this->_setQueryConditions($conditions, $query);

            foreach ($globalTotalRowConfig as $field => $globalTotalRowItemConfig) {
                $expr = $globalTotalRowItemConfig[BFC::GLOBAL_TOTAL_ROW_EXP];
                $query->field($expr . " as " . $field);
            }
            $globalTotalRowResult = $query->find();
        }

        $this->success("ok", null, $globalTotalRowResult);
    }

    /**
     * 全局汇总区域配置
     *
     * @return array
     */
    protected function _getGlobalTotalRowConfig() {
        return [];
    }

    /**
     * 结果预处理
     *
     * @param $result
     * @return mixed
     */
    protected function _resultPreProcess(&$result) {
        if (!isset($result['data']) || empty($result['data'])) {
            return $result;
        }
        foreach ($result['data'] as &$row) {
            $this->_rowPreProcess($row);
        }
        return $result;
    }

    /**
     * 行数据预处理
     *
     * @param $row
     * @return mixed
     */
    protected function _rowPreProcess(&$row) {
        return $row;
    }

    /**
     * 获取单行数据
     *
     * @throws \think\Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     * @throws \think\exception\PDOException
     */
    public function row() {
        $query = $this->_q();
        $fieldsConfig = $this->_getBeanFieldsConfig();
        $fields = $this->_getSelectFields($fieldsConfig);
        $query->field(join(",", $fields));

        // 查询条件
        $conditions = $this->_getKeyConditions();
        if ($this->_enableEid()) {
            $conditions['enterprise_id'] = $this->eid;
        }
        if ($this->_isSoftDelete()) {
            $conditions['is_deleted'] = 0;
        }
        $query->where($conditions);

        // 查询数据
        $row = $query->find();
        if ($row) {
            $this->_rowPreProcess($row);
        }

        $this->success("ok", null, $row);
    }

    /**
     * 数据删除
     *
     * @throws \think\Exception
     * @throws \think\exception\PDOException
     */
    public function del() {
        $condition = $this->_getKeyConditions();
        if (empty($condition)) {
            $this->error(lang("BEAN_KEY_FIELD_MISS"));
        }

        //查找对应的原始记录
        $oldRecords = $this->_q()->where($condition)->select();
        if (empty($oldRecords)) {
            $this->error(lang("BEAN_NOT_FOUND"));
        }
        if (count($oldRecords) > 1) {
            $this->error(lang("BEAN_CAN_NOT_OPER_BATCH"));
        }
        $oldRecord = $oldRecords[0];

        if (is_submit()) {
            //数据删除之前
            $this->_beforeDel($oldRecord, $condition);

            if ($this->_isSoftDelete()) {
                //软删除
                $updateData = [
                    'is_deleted' => 1
                ];
                if ($this->_gmtModified()) {
                    $updateData['gmt_modified'] = time();
                }
                $ret = $this->_q()->where($condition)->limit(1)->update($updateData);
            } else {
                //物理删除
                $ret = $this->_q()->where($condition)->limit(1)->delete();
            }
            if ($ret) {
                //数据删除成功
                $this->_afterDelSuccess($oldRecord, $condition);
                $this->success(lang("DEL_SUCCESS"));
            } else {
                $this->error(lang("DEL_FAIL"));
            }
        } else {
            $this->assign("record", $oldRecord);
            $this->_beforeShowDel($condition, $oldRecord);
            return view();
        }
    }

    /**
     * 显示删除页面之前
     *
     * @param $condition
     * @param $oldRecord
     */
    protected function _beforeShowDel(&$condition, $oldRecord) {
    }

    /**
     * 真正删除数据之前
     *
     * @param $oldRecord
     * @param $condition
     */
    protected function _beforeDel($oldRecord, $condition) {
    }

    /**
     * 数据删除成功回调
     *
     * @param $oldRecord
     * @param $condition
     */
    protected function _afterDelSuccess($oldRecord, $condition) {
    }

    /**
     * 数据新增
     *
     * @return \think\response\View
     * @throws \think\Exception
     */
    public function add() {
        if (is_submit()) {
            $row = request()->param(false);
            //去除无用的列
            $beanFieldsConfig = $this->_getBeanFieldsConfig();
            $rowFields = array_keys($row);
            foreach ($rowFields as $field) {
                if (!isset($beanFieldsConfig[$field])) {
                    unset($row[$field]);
                }
            }
            if ($this->_enableEid()) {
                $row['enterprise_id'] = $this->eid;
            }
            if ($this->_isSoftDelete()) {
                $row['is_deleted'] = 0;
            }
            if ($this->_gmtCreated()) {
                $row['gmt_created'] = time();
            }
            if ($this->_gmtModified()) {
                $row['gmt_modified'] = time();
            }


            //数据增加之前
            $this->_beforeAdd($row);
            $query = $this->_q();
            $ret = $query->insertGetId($row);
            if (empty($ret)) {
                $this->error(lang("ADD_FAIL"));
            } else {
                //数据保存成功
                $this->_afterAddSuccess($row, $ret);
                $this->success(lang("ADD_SUCCESS"), null, [
                    'key' => $ret
                ]);
            }
        } else {
            $this->_beforeShowAdd();
            return view();
        }
    }

    /**
     * 显示新增页面之前
     */
    protected function _beforeShowAdd() {

    }

    /**
     * 数据即将被新增之前
     *
     * @param $row
     */
    protected function _beforeAdd(&$row) {

    }


    /**
     * 数据新增成功回调
     *
     * @param $row
     * @param $id
     */
    protected function _afterAddSuccess($row, $id) {
    }

    /**
     * 更新单条数据
     *
     * @throws \think\Exception
     * @throws \think\exception\PDOException
     */
    public function edit() {
        $params = request()->param(false);

        //去除无用的列
        $beanFieldsConfig = $this->_getBeanFieldsConfig();
        $rowFields = array_keys($params);
        foreach ($rowFields as $field) {
            if (!isset($beanFieldsConfig[$field])) {
                unset($params[$field]);
            }
        }

        $condition = $this->_getKeyConditions($params, true);
        if (empty($condition)) {
            $this->error(lang("BEAN_KEY_FIELD_MISS"));
        }
        if ($this->_enableEid()) {
            $condition['enterprise_id'] = $this->eid;
        }
        if ($this->_isSoftDelete()) {
            $condition['is_deleted'] = 0;
        }
        //原始记录
        $oldRecords = $this->_q()->where($condition)->select();
        if (empty($oldRecords)) {
            $this->error(lang("BEAN_NOT_FOUND"));
        }
        if (count($oldRecords) > 1) {
            $this->error(lang("BEAN_CAN_NOT_OPER_BATCH"));
        }
        $oldRecord = $oldRecords[0];

        if (is_submit()) {
            if ($this->_gmtModified()) {
                $params['gmt_modified'] = time();
            }
            //数据更新之前
            $this->_beforeEdit($oldRecord, $condition, $params);
            $ret = $this->_q()->where($condition)->limit(1)->update($params);
            if ($ret) {
                //数据更新成功
                $this->_afterEditSuccess($oldRecord, $condition, $params, $ret);
                $this->success(lang("EDIT_SUCCESS"));
            } else {
                $this->error(lang("EDIT_FAIL"));
            }
        } else {
            $this->assign("record", $oldRecord);
            $this->_beforeShowEdit($condition, $oldRecord);
            return view();
        }
    }

    /**
     * 显示编辑页面之前
     *
     * @param $condition
     * @param $oldRecord
     */
    protected function _beforeShowEdit($condition, $oldRecord) {
    }

    /**
     * 数据执行更新前调用
     *
     * @param $oldRecord
     * @param $condition
     * @param $params
     */
    protected function _beforeEdit($oldRecord, &$condition, &$params) {
    }

    /**
     * 数据更新成功回调
     *
     * @param $oldRecord
     * @param $condition
     * @param $params
     * @param $effectRowCount
     */
    protected function _afterEditSuccess($oldRecord, $condition, $params, $effectRowCount) {
    }

    /**
     * 从参数中获取查询条件
     *
     * @param $fieldsConfig
     * @return array
     */
    protected function _getQueryConditions($fieldsConfig) {
        return $this->_getDefaultQueryConditions($fieldsConfig);
    }

    /**
     * 从参数中获取查询条件
     *
     * @param $fieldsConfig
     * @return array
     */
    protected function _getDefaultQueryConditions($fieldsConfig) {
        $conditions = [];
        $params = $this->request->post("___where");
        $params = json_decode($params, true);
        foreach ($fieldsConfig as $field => $fieldConfig) {
            if (!isset($fieldConfig['search']) || !$fieldConfig['search']) {
                // 该字段没有开启搜索
                continue;
            }

            if (!isset($params[$field])) {
                continue;
            }

            $param = $params[$field];
            if (empty($param) || !isset($param['val']) || $param['val'] === "" || $param['val'] === []) {
                continue;
            }

            $condition = [
                $param['oper'],
                $param['val']
            ];
            $conditions[$field] = $condition;
        }
        if ($this->_isSoftDelete()) {
            $conditions['is_deleted'] = 0;
        }
        if ($this->_enableEid()) {
            $conditions['enterprise_id'] = $this->eid;
        }
        return $conditions;
    }

    /**
     * 将查询条件生成文本的sql
     *
     * @param $field
     * @param $condition
     * @return string
     */
    private function _getRawCondition($field, $condition) {
        $raw = $field;
        if (is_array($condition)) {
            $oper = $condition[0];
            $value = $condition[1];
            $exp = [
                'eq' => '=', 'neq' => '<>', 'gt' => '>', 'egt' => '>=', 'lt' => '<', 'elt' => '<=',
                'notlike' => 'NOT LIKE', 'not like' => 'NOT LIKE', 'like' => 'LIKE', 'in' => 'IN',
                'exp' => 'EXP', 'notin' => 'NOT IN', 'not in' => 'NOT IN', 'between' => 'BETWEEN',
                'not between' => 'NOT BETWEEN', 'notbetween' => 'NOT BETWEEN', 'exists' => 'EXISTS',
                'notexists' => 'NOT EXISTS', 'not exists' => 'NOT EXISTS', 'null' => 'NULL',
                'notnull' => 'NOT NULL', 'not null' => 'NOT NULL', '> time' => '> TIME', '< time' => '< TIME',
                '>= time' => '>= TIME', '<= time' => '<= TIME', 'between time' => 'BETWEEN TIME',
                'not between time' => 'NOT BETWEEN TIME', 'notbetween time' => 'NOT BETWEEN TIME'
            ];
            switch ($oper) {
                case 'between':
                    if (is_string($value[0])) {
                        $value[0] = "'" . $value[0] . "'";
                    }
                    if (is_string($value[1])) {
                        $value[1] = "'" . $value[1] . "'";
                    }
                    $value = $value[0] . " and " . $value[1];
                    break;
                case 'like':
                    $value = "'%" . $value . "%'";
                    break;
                default:
                    if (is_string($value)) {
                        $value = "'" . $value . "'";
                    }
                    break;
            }
            if (isset($exp[$oper])) {
                $oper = $exp[$oper];
            }
            $raw .= " " . $oper . " " . $value;
        } else {
            if (is_string($condition)) {
                $condition = "'" . $condition . "'";
            }
            $raw .= " = " . $condition;
        }

        return $raw;
    }

    /**
     * 解析order
     *
     * @param $orderParam
     * @return array
     * @throws \think\Exception
     * @throws \think\exception\PDOException
     */
    private function _parseOrder($orderParam) {
        $fieldsConfig = $this->_getBeanFieldsConfig();

        $orderItems = [];
        if (!empty($orderParam)) {
            $orderParamItems = explode(";", $orderParam);
            foreach ($orderParamItems as $orderParamItem) {
                $tokens = explode(",", $orderParamItem);
                $orderFieldName = $tokens[0];
                $orderType = 'desc';
                if (!array_key_exists($orderFieldName, $fieldsConfig)) {
                    continue;
                }
                $fieldConfig = $fieldsConfig[$orderFieldName];
                if (isset($fieldConfig[BFC::VIRTUAL]) && is_string($fieldConfig[BFC::VIRTUAL])) {
                    //虚拟计算字段
                    $orderFieldName = $fieldConfig[BFC::VIRTUAL];
                }

                if (count($tokens) > 1) {
                    $orderType = $tokens[1];
                }
                $orderItems[$orderFieldName] = $orderType;
            }
        } else {
            $orderItems = $this->_getDefaultOrder();
        }

        $strOrder = [];
        foreach ($orderItems as $col => $orderType) {
            $strOrder[] = $col . " " . $orderType;
        }

        return [
            join($strOrder, ","), $orderItems
        ];
    }

    /**
     * 列按照index顺序进行排序
     *
     * @param $fieldsConfig
     * @return mixed
     */
    private function _sortFieldsConfigByIndex($fieldsConfig) {
        $sortedFieldsConfigKeys = [];
        $sortedFieldsConfigValues = [];

        foreach ($fieldsConfig as $fieldName => $fieldConfig) {
            $insertPosition = false;
            $colIndex = fetch($fieldConfig, BFC::COL_INDEX, PHP_INT_MAX);
            for ($i = 0; $i < count($sortedFieldsConfigValues); $i++) {
                $currColIndex = fetch($sortedFieldsConfigValues[$i], BFC::COL_INDEX, PHP_INT_MAX);
                if ($colIndex >= $currColIndex) {
                    continue;
                }
                $insertPosition = $i;
                break;
            }

            if (!$insertPosition) {
                array_push($sortedFieldsConfigKeys, $fieldName);
                array_push($sortedFieldsConfigValues, $fieldConfig);
            } else {
                array_splice($sortedFieldsConfigKeys, $insertPosition, 0, $fieldName);
                array_splice($sortedFieldsConfigValues, $insertPosition, 0, array($fieldConfig));
            }
        }

        $sortedFieldsConfig = [];
        for ($i = 0; $i < count($sortedFieldsConfigValues); $i++) {
            $sortedFieldsConfig[$sortedFieldsConfigKeys[$i]] = $sortedFieldsConfigValues[$i];
        }

        return $sortedFieldsConfig;
    }

    /**
     * 获取主键key参数条件
     *
     * @param bool $params
     * @param bool $unset
     * @return array|bool
     * @throws \think\Exception
     * @throws \think\exception\PDOException
     */
    private function _getKeyConditions(&$params = false, $unset = false) {
        $keyFieldNames = [];
        foreach ($this->_getBeanFieldsConfig() as $fieldName => $fieldConfig) {
            if (isset($fieldConfig['key']) && $fieldConfig['key']) {
                $keyFieldNames[] = $fieldName;
            }
        }

        if ($params === false) {
            $params = request()->param(false);
        }
        $condition = [];
        foreach ($keyFieldNames as $keyFieldName) {
            if (!isset($params[$keyFieldName])) {
                // 必须所有设置为key的字段都指定
                return false;
            }
            $condition[$keyFieldName] = $params[$keyFieldName];
            if ($unset) {
                unset($params[$keyFieldName]);
            }
        }
        return $condition;
    }

    /**
     * 获取查询字段列表
     *
     * @param $fieldsConfig
     * @return array
     */
    private function _getSelectFields($fieldsConfig) {
        $fields = [];
        foreach ($fieldsConfig as $field => $fieldConfig) {
            if (isset($fieldConfig[BFC::VIRTUAL])) {
                if (is_string($fieldConfig[BFC::VIRTUAL])) {
                    $fields[] = $fieldConfig[BFC::VIRTUAL] . " as " . $field;
                }
                continue;
            }
            $fields[] = $field;
        }
        return $fields;
    }

    /**
     * 设置query对象的查询条件
     *
     * @param $conditions
     * @param $query
     * @return mixed
     * @throws \think\Exception
     * @throws \think\exception\PDOException
     */
    protected function _setQueryConditions($conditions, $query) {
        $fieldsConfig = $this->_getBeanFieldsConfig();

        foreach ($conditions as $field => $condition) {
            $fieldConfig = fetch($fieldsConfig, $field);
            if (!empty($fieldConfig) && isset($fieldConfig[BFC::VIRTUAL]) && is_string($fieldConfig[BFC::VIRTUAL])) {
                $rawCondition = $this->_getRawCondition($fieldConfig[BFC::VIRTUAL], $condition);
                $query = $query->where($rawCondition);
            } else {
                if ($condition instanceof Expression) {
                    $query = $query->where($condition->__toString());
                } else if (is_array($condition)) {
                    $query = $query->where($field, $condition[0], $condition[1]);
                } else {
                    $query = $query->where($field, $condition);
                }
            }
        }
        return $query;
    }

    /**
     * 获取有权限的按钮
     *
     * @param $btns
     * @return array
     */
    protected function _getAuthorizedBtns($btns) {
        if (!method_exists($this, "_hasModuleAuthority") || !isset($this->mid)) {
            return $btns;
        }
        $authorizedBtns = [];
        foreach ($btns as $key => $btn) {
            $authority = fetch($btn, BFC::AUTHORITY);
            if ($authority && !$this->_hasModuleAuthority($this->mid, $authority)) {
                continue;
            }
            $authorizedBtns[$key] = $btn;
        }
        return $authorizedBtns;
    }

}